package pluginTest;

import static org.junit.Assert.*;
import java.util.Scanner;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.List;

import org.junit.Test;

import Phase2.Node;
import Phase2Tests.DistributedTest;
import plugin.BroadcastAlgorithm;
import plugin.BroadcastWithAck;
import plugin.Broadcast;
import plugin.KeyValuePair;
import plugin.SendMessage;
import plugin.Visitor;

public class VisitorTests 
{
	private Node baseNode;
	
	public void setUp()
	{
		this.baseNode = new Node();
	}
	
	public void tearDown()
	{
		
	}

	@SuppressWarnings("unchecked")
	@Test
	public void broadcastAlgorithmTest() throws InterruptedException
	{
		List<Node> nodes = new ArrayList<Node>();
		this.baseNode = new Node();
		nodes.add(this.baseNode);
		
		Node temp = new Node();
		
		
		for (int i = 1; i < 2; i++)
		{
			temp = new Node();
			this.baseNode.insert(temp);
			nodes.add(temp);
		}
		
		Visitor alg = new BroadcastAlgorithm();
		List<Node> results = (List<Node>) alg.visit(nodes.get(1), nodes.get(1).getId(false));
		
		DistributedTest.print("Results are:");
		for (Node node : results)
		{
			DistributedTest.print(node.toString());
		}
	}
	
	@Test
	public void broadcastTest() throws InterruptedException
	{
		System.out.print("\nTEST broadcastTest");
		List<Node> nodes = new ArrayList<Node>();
		this.baseNode = new Node();
		nodes.add(this.baseNode);
		
		Node temp = new Node();
		
		Visitor broadcast = new Broadcast();
		
		for (int i = 1; i < 100; i++)
		{
			temp = new Node();
			this.baseNode.insert(temp);
			nodes.add(temp);
		}
		
		//this.baseNode.accept(broadcast, "Hello");
		nodes.get(2).accept(broadcast, "Hello");
		System.out.println("...PASSED!");
	}
	@SuppressWarnings("unchecked")
	@Test
	public void broadcastWithAckTest() throws InterruptedException
	{
		System.out.print("\nTEST broadcastWithAckTest");
		final int SIZE = 7;
		TreeSet<Node> nodes = new TreeSet<Node>();
		this.baseNode = new Node();
		nodes.add(this.baseNode);
		
		Node temp = new Node();
		Visitor broadcast = new BroadcastWithAck();
		
		for (int i = 1; i < SIZE; i++)
		{
			temp = new Node();
			this.baseNode.insert(temp);
			nodes.add(temp);
		}
		ArrayList<Object> t = (ArrayList<Object>) this.baseNode.acceptWithResponse(broadcast, "Hello");
		//ArrayList<Object> t = (ArrayList<Object>) this.baseNode.getNeighbour(2).getNeighbour(3).acceptWithResponse(broadcast, "Hello");
		assertEquals(SIZE, t.size());
		assertTrue(t.containsAll(nodes));
		//System.out.println("ack returns these nodes" + t.toString());
		//System.out.print("size:"+t.size()+t);
		System.out.println("...PASSED!");
	}
	
	@SuppressWarnings("unchecked")
	@Test
	public void multipleBroadcasts() throws InterruptedException
	{
		System.out.println("\nTest Multiple Broadcasts");
		final int SIZE = 73;
		//TreeSet<Integer> nodeIDs = new TreeSet<Integer>();
		ArrayList<Node> webNodes = new ArrayList<Node>();
		Visitor broadcast = new BroadcastWithAck();
		
		for (int i = 1; i < SIZE; i++)
		{
			Node temp;
			this.baseNode = new Node();
			webNodes.add(baseNode);
			for (int j = 0; j < i; j++)
			{
				temp = new Node();
				this.baseNode.insert(temp);
				//nodeIDs.add(temp.getId());
				webNodes.add(temp);
			}
			assertTrue(webNodes.size() == i + 1);
			for (int k = 0; k < webNodes.size(); k++)
			{
				ArrayList<Object> t = (ArrayList<Object>) webNodes.get(k).acceptWithResponse(broadcast, "Hello");
				assertEquals(webNodes.size(), t.size());
				assertTrue(t.containsAll(webNodes));
				t.clear();
			}
			System.out.println("BROADCAST PASSED WITH " + webNodes.size() + " NODES");
			//nodeIDs.clear();
			webNodes.clear();
		}
	}
	
	@Test
	public void sendMessage() throws InterruptedException
	{
		int size;
		int idFrom;
		int idTo;
		boolean rootAccess = false;
		Node nodeAdded;
		Node baseNode;
		ArrayList<Node> hypeerWeb = new ArrayList<Node>();
		SendMessage sender = new SendMessage();
		String note;
		KeyValuePair<Integer, String> message;
		
		Scanner scan = new Scanner(System.in);
		System.out.println("Enter the size of the Hypeer Web to be created: ");
		size = scan.nextInt();
		baseNode = new Node();
		hypeerWeb.add(baseNode);
		for (int i = 0; i < size - 1; i++)
		{
			nodeAdded = new Node();
			baseNode.insert(nodeAdded);	
			hypeerWeb.add(nodeAdded);
		}
		System.out.println("Hypeer Web of size " + size + " created.");
		System.out.println("Enter the ID of the Node to be broadcast from: ");
		idFrom = scan.nextInt();
		System.out.println("Enter the ID of the Node to broadcast to: ");
		idTo = scan.nextInt();
		System.out.println("Enter the string to be sent as a message: ");
		note = scan.next();
		
		message = new KeyValuePair<Integer, String>(idTo, note);
		hypeerWeb.get(idFrom).acceptWithResponse(sender, message);
		System.out.println("Message sent.");
		
		System.out.println("Message recieved is: \"" + hypeerWeb.get(idTo).getPayload("message") + "\" at Node: " 
				+ hypeerWeb.get(idTo).getId(rootAccess));
		
	}
}
